iT邦幫忙

2023 iThome 鐵人賽

DAY 5
0
DevOps

大家都在用 Terraform 實作 IaC 為什麼不將程式寫得更簡潔易讀呢?系列 第 5

如何利用 HCL 語言的撰寫 Terraform 專案的基本介紹 (Part V) - 使用 tfvars 多環境佈署

  • 分享至 

  • xImage
  •  

使用 Terraform 的 .tfvars 文件(通常是 .tfvars 或 .auto.tfvars)有幾個好處:

  • 分離變數和代碼: 使用 .tfvars 文件,你可以將變數值從 Terraform 代碼中分離出來。這使得代碼更容易閱讀、維護和共享,並且允許不同的環境使用相同的代碼但具有不同的變數值。
  • 參數化配置: 使用 .tfvars 文件,你可以根據不同的需求自定義配置。這使得配置變得參數化,可以輕鬆應對不同的情境,如開發、測試和生產。
  • 安全性: 通常 .tfvars 文件可以加密或保護,以防止未授權的訪問。這有助於保護敏感資訊,如密碼、金鑰等。
  • 易於共享和管理: 你可以輕鬆地將 .tfvars 文件與團隊中的其他成員共享,並協作編輯。這有助於確保配置的一致性。
  • 多環境支持: 通過為不同的環境(例如,開發、測試、生產)建立不同的 .tfvars 文件,你可以在不同環境中使用相同的 Terraform 代碼。
  • 命令行選項: 你可以使用 -var-file 選項來指定要在執行 Terraform 命令時使用的 .tfvars 文件,這使得自動化和 CI/CD 流程更容易管理。
  • 避免 Hard Code: 使用 .tfvars 文件,你可以避免在 Terraform 代碼中硬編碼變數值,這樣如果需要更改變數值,你只需編輯 .tfvars 文件而不必修改代碼。

以下我會使用稍早的的代碼來介紹使用 .tfvars 文件的方式,要再新增三個檔案 variables.tftokyo.tfvarsosaka.tfvars,文件結構如下:

├── main.tf
├── modules
│   └── ec2_instances
│       ├── data.aws_ami.ami.tf
│       ├── main.tf
│       ├── provider.tf
│       └── variables.tf
├── osaka.tfvars
├── provider.tf
├── tokyo.tfvars
└── variables.tf
  1. variables.tf: 來定義哪些變數可以動態變數方式傳入,例如:aws_regionaws_profileinstance_countinstance_typeenvironment
ariable "aws_region" {
  type        = string
  description = "AWS Region"
}

variable "aws_profile" {
  type        = string
  description = "Profile in .aws/config"
}

variable "instance_count" {
  type = number
  description = "Number of EC2 instances to create"
}

variable "instance_type" {
  type = string
  description = "The type of EC2 instance"
}

variable "ami_id" {
  type = string
  description = "The ID of the AMI"
  default     = null
}

variable "environment" {
    type = string
    description = "The environment of EC2 instance"
}
  1. tokyo.tfvars:定義需要佈署在 Tokyo region 資源的變數內容。
aws_region     = "ap-northeast-1"
aws_profile    = "<YOUR_PROFILE>"
instance_count = 1
instance_type  = "t3a.micro"
environment    = "Osaka"
  1. osaka.tfvars:定義需要佈署在 Osaka region 資源的變數內容。
aws_region     = "ap-northeast-3"
aws_profile    = "<YOUR_PROFILE>"
instance_count = 2
instance_type  = "t3a.small"
environment    = "Osaka"

接下來,我們來試著用不同 .tfvars 來執行計畫看看輸出結果。

  • 先執行 terraform plan --out .plan -var-file=tokyo.tfvars 帶入 tokyo.tfvars 變數檔案後輸出結果如下:
module.my_ec2_instances.data.aws_ami.selected_ami: Reading...
module.my_ec2_instances.data.aws_ami.selected_ami: Read complete after 0s [id=ami-0f419d2f905bb344e]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.my_ec2_instances.aws_instance.example[0] will be created
  + resource "aws_instance" "example" {
      + ami                                  = "ami-0f419d2f905bb344e"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_lifecycle                   = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t3a.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = (known after apply)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + spot_instance_request_id             = (known after apply)
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Environment" = "Dev"
          + "Name"        = "ec2-instance-0"
        }
      + tags_all                             = {
          + "Environment" = "Dev"
          + "Name"        = "ec2-instance-0"
        }
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

───────────────────────────────────────────────────────────────────────

Saved the plan to: .plan

To perform exactly these actions, run the following command to apply:
    terraform apply ".plan"
  • 先執行 terraform plan --out .plan -var-file=osaka.tfvars 帶入 osaka.tfvars 變數檔案後輸出結果如下:
module.my_ec2_instances.data.aws_ami.selected_ami: Reading...
module.my_ec2_instances.data.aws_ami.selected_ami: Read complete after 1s [id=ami-035f22189112edf2e]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
  + create

Terraform will perform the following actions:

  # module.my_ec2_instances.aws_instance.example[0] will be created
  + resource "aws_instance" "example" {
      + ami                                  = "ami-035f22189112edf2e"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_lifecycle                   = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t3a.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = (known after apply)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + spot_instance_request_id             = (known after apply)
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Environment" = "Dev"
          + "Name"        = "ec2-instance-0"
        }
      + tags_all                             = {
          + "Environment" = "Dev"
          + "Name"        = "ec2-instance-0"
        }
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)
    }

  # module.my_ec2_instances.aws_instance.example[1] will be created
  + resource "aws_instance" "example" {
      + ami                                  = "ami-035f22189112edf2e"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_lifecycle                   = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t3a.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = (known after apply)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + spot_instance_request_id             = (known after apply)
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Environment" = "Dev"
          + "Name"        = "ec2-instance-1"
        }
      + tags_all                             = {
          + "Environment" = "Dev"
          + "Name"        = "ec2-instance-1"
        }
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

───────────────────────────────────────────────────────────────────────

Saved the plan to: .plan

To perform exactly these actions, run the following command to apply:
    terraform apply ".plan"

從上述執行計畫結果,它會以不同 .tfvars 內給定的變數內容來決定佈署到不同環境,且使用同一份模組代碼可以動態決定佈署的資源項目非常的方便。


你可以使用 git-secret 工具幫助你安全地加密 Terraform 的 .tfvars 文件,以防止未經授權的訪問,步驟如下:

  1. 初始化 git-secret: 在你的 Git repository 中,首先初始化 git-secret,在 repository 當前目錄中運行以下命令:
git secret init
  1. 新增 .gitignore 文件: 將 .tfvars 文件不要新增到 Git repository 中。
echo "*..tfvars" > .gitignore
  1. 加密文件: 使用 git secret add 命令將文件加密與 git secret hide -m 將檔案進行加密儲存。
git secret add tokyo.tfvars
git secret add osaka.tfvars
git secret hide -m
  1. 確認變更: 使用 git addgit commit 命令確認變更。
git add .gitignore
git add *.secret
git commit -m "Add encrypted .tfvars file"
  1. Push 變更: 推送你的變更到 Git repository。
git push

下一天,將說明如何實作多個模組間相依性。


上一篇
如何利用 HCL 語言的撰寫 Terraform 專案的基本介紹 (Part IV) - 套用 HCL 代碼
下一篇
如何利用 HCL 語言的撰寫 Terraform 專案的基本介紹 (Part VI) - 模組間相依性
系列文
大家都在用 Terraform 實作 IaC 為什麼不將程式寫得更簡潔易讀呢?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言